iT邦幫忙

2023 iThome 鐵人賽

DAY 18
0
Modern Web

從Vue學React!不只要會用,還要真的懂~系列 第 18

【Day 18】優化頁面效能的另一個方向-lazy & Suspense

  • 分享至 

  • xImage
  •  

前面我們連續看了兩個對避免畫面重新渲染有幫助的hook,今天緊接著再來看另一個也有助於優化效能,並提升使用者體驗的方式。之前看的幾個hooks,主要都是透過避免元件進行多餘的重新渲染,或避免進行多餘計算的方式來改善頁面的效能,今天的主題「lazy」和「Suspense」則是透過**「拆分程式碼」和「動態載入」,以及「避免畫面渲染阻塞」**的方式來改善效能和使用者體驗。

lazy和Suspense是什麼?

「lazy」是React用來處理元件「動態載入」的功能,所謂的動態載入,白話一點來說明的話,也就是需要某個JavaScript檔案時,才把這個檔案載入,也就可以避免一開始進入畫面時,花太多時間載入一些當前頁面不需要的JavaScript。而這樣的作法,也可以達到拆分程式碼(Code Splitting)的效果 ,因為每個用lazy處理的元件會被獨立成一個JavaScript檔案,就不再是一大包內含所有元件程式碼的JavaScript檔案。

「Suspense」是React提供來優化使用者體驗的功能,使用Suspense可以在非同步處理,或是動態加載元件時的等待狀態,例如在等待時間先在畫免顯示loading文字,讓使用者感覺網頁有一直在動,而不是停止不動,等到資料載完,再顯示預定要顯示的畫面。雖然「Suspense」常與 「lazy」一起使用以實現程式碼拆分和動態加載,但它也可以單獨用於處理非同步操作的等待。

lazy和Suspense的使用方式

大概了解suspense和lazy是什麼用途後,接著來看看要怎麼使用lazy和suspense。

lazy

當我們要把元件變成lazy loaded的元件的時候,可以這樣做。

// 先import lazy
import { lazy } from 'react';

// 再宣告lazy loaded元件
const ALazyLoadedComponent = lazy(() => import ('./components/AComponent'));

如果想要讓切分出來的程式碼,能有指定的命名的話,還可以用下面的方式命名。

// 先import lazy
import { lazy } from 'react';

// 可以這樣加上webpackChunkName,讓切分出來的程式碼能被標示上指定的的名字
const ALazyLoadedComponent = lazy(() => import (/* webpackChunkName: "AComponent" */'./components/AComponent'));

沒有指定命名時,加載進來的檔名會顯示成這樣。
https://ithelp.ithome.com.tw/upload/images/20230922/20130914outOCpjzj3.png

有指定命名時,則會依照指定的名字顯示。
https://ithelp.ithome.com.tw/upload/images/20230922/20130914w19H8FJxhp.png

Suspense

當我們使用lazy或是進行一些非同步拉取資料的動作時,中間有可能會有一小段等待時間,這時候就可以這樣使用Suspens來處理。

import { lazy, Suspense, useState } from 'react';

const ALazyLoadedComponent = lazy(() => import ('./components/AComponent'));

function App() {  
  return (
    <div className="App">
        <Suspense fallback="loading">
          <ALazyLoadedComponent /> 
        </Suspense>
    </div>
  );
}

https://i.imgur.com/osIbp1o.gif

Suspense不僅適合搭配lazy loaded元件一起使用,也很適合拿來優化打api拉取到資料之前的狀態。以前可能需要自己寫個isLoading的值拿來切換資料回來前和回來後的畫面轉變,使用Suspense,就不需要額外再寫一個值做判斷。因為Suspense會在chrilderen渲染被block住的時候,先渲染fallback的內容,以提供使用者更好的使用體驗。

lazy和Suspense使用前後的差異

知道怎麼使用之後,緊接著再來看看有沒有使用lazy和Suspense差異到底在哪裡?
這裡的例子以一個單純的例子來示範:
這個例子的情境是畫面上顯示什麼子元件會依照一個state來決定,所以當這個被拿來判斷要顯示哪個元件的state被更改之前,另一個元件有沒有被載入對畫面都的顯示都不會有影響。

{
  isAComponent ? <AComponent /> : <BComponent /> 
}

尚未使用lazy和Suspense時
在沒有使用lazy搭配Suspen之前,不管是不是當下要使用的元件都會在一進入畫面的時候就被載入。所以如果觀察Dev Tools內的network的話,可以發現載入的bundle.js內含AComponent和BComponent的內容。
https://ithelp.ithome.com.tw/upload/images/20230922/20130914MJf60gKbyC.png
https://ithelp.ithome.com.tw/upload/images/20230922/20130914nSFyg8qn57.png

使用lazy和Suspense之後
在使用lazy搭配Suspense後,會發現原本的bundle.js沒有直接包含這兩個元件的內容了,取得代之的是多了兩個新的js檔案,而且不會在一開始載入畫面的時候就把兩個js檔案都載入,只會在第一次用到的時候再載入。
https://i.imgur.com/DcVIIUZ.gif
這樣能達到的效果也就是前面所提到過的「減少第一次載入畫面時,需要載入的js檔案大小,將js的程式碼拆分,等到需要的時候,再載入」,也因為是以這樣的方式下去載入js檔案,就能加快畫面載入的速度。

Vue也有類似的用法?

雖然前面都一直讓男主角React出現,但我們可不能忘了我們的男二Vue啊!其實Vue也有類似lazy的動態載入元件的方式,不過大多都是搭配vue-router一起做使用,例如以下的這種寫法。

const routes = [
  {
    path: '/',
    name: 'Home',
    // 元件lazy load的部分
    component: () => import(/* webpackChunkName: "home" */ '../views/Home.vue'),
  },
  // 其他router的設定...
];

如果單獨使用的話,則可以透過defineAsyncComponent來定義lazy loaded元件。

import { defineAsyncComponent } from 'vue'

const LazyLoadedComponent = defineAsyncComponent(() =>
  import('./components/AComponent.vue')
)

除了lazy的功能外,Vue也有Suspense的功能,不過這個功能還在實驗性質,所以可能還不太穩定,可以稍微參考一下就好。在用法上跟React很類似,一樣是將Suspense包在最外圍,但是裡面的內容是用template區分不同時機點顯示的內容。

<template>
  <div>
    <!-- 當非同步的動作處理完後,就會顯示default的內容 -->
    <Suspense>
      <template #default>
        <AsyncComponent />
      </template>
      <!-- 如果非同步動作還沒進行完畢,則會顯示fallback的內容 -->
      <template #fallback>
        <Loading />
      </template>
    </Suspense>
  </div>
</template>

總結

今天又看了一種與效能優化有關的作法,有別於之前提到「避免多餘的重新渲染」以及「避免多餘的重新計算」,今天看的lazy和suspense主要是用於將js檔案拆小,並以動態載入的方式,避免初次進入畫面,就載入所有當前頁面不需要的程式碼,並透過suspense讓畫面渲染出現阻塞狀況時,先載入一個加載中的畫面,以提升使用者體驗。雖然lazy和suspense的功能在React和Vue中都有,但是使用上稍微有些差異,且Suspense的功能在Vue中還在實驗階段,所以使用時,可能要多留意一下這部分。

參考資料

[Vue]Suspense
[React]Suspense


上一篇
【Day 17】想要避免多餘的渲染就用它?了解useCallback的最終目的
下一篇
【Day 19】認識Controlled & Uncontrolled Component
系列文
從Vue學React!不只要會用,還要真的懂~30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言